﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using XXF.BaseService.ServiceCenter.Dal;
using XXF.BaseService.ServiceCenter.Service.Protocol;
using XXF.BaseService.ServiceCenter.SystemRuntime;
using XXF.ProjectTool;

namespace XXF.BaseService.ServiceCenter.Client.Provider
{
    /// <summary>
    /// 客户端提供类
    /// </summary>
    public class ClientProvider : IDisposable
    {
        protected ClientContext _context;
        public string ServiceNamespace { get; set; }
        public ClientProvider(string servicenamespace)
        {
            if (string.IsNullOrWhiteSpace(servicenamespace))
                throw new ServiceCenterException("服务命名空间不能为空");
            ServiceNamespace = servicenamespace;
        }
        /// <summary>
        /// 注册客户端
        /// </summary>
        public void Register()
        {
            try
            {
                if (_context == null)
                {
                    ClientContext context = new ClientContext();
                    SqlHelper.ExcuteSql(SystemConfigHelper.ServiceCenterConnectString, (c) =>
                    {
                        //服务获取
                        tb_service_dal serverdal = new tb_service_dal();
                        context.ServiceModel = serverdal.Get(c, ServiceNamespace);
                        if (context.ServiceModel == null)
                            throw new ServiceCenterException(string.Format("该{0}服务命名空间未注册,请在服务中心站点注册.", ServiceNamespace));
                        ServiceNamespace = context.ServiceModel.servicenamespace;
                        //获取服务可用协议
                        tb_protocolversion_dal protocaldal = new tb_protocolversion_dal();
                        context.ProtocolVersionModel = protocaldal.Get(c, context.ServiceModel.id, context.ServiceModel.protocolversion);
                        if (context.ProtocolVersionModel == null)
                            throw new ServiceCenterException(string.Format("该{0}服务命名空间找不到可用协议,请在服务中心指定协议", ServiceNamespace));
                        //服务节点获取
                        tb_node_dal nodedal = new tb_node_dal();
                        var nodes = nodedal.GetAllListOnLine(c, context.ServiceModel.id, SystemParamConfig.Node_HeatBeat_Time_Out);
                        context.NodeModels = nodes;

                        //注册客户端
                        long sessionid = CommonHelper.CreateSessionIDOfClient(context.ServiceModel.servicenamespace.ToLower());
                        tb_client_dal clientdal = new tb_client_dal();
                        var clientmodel = clientdal.Get(c, sessionid);
                        if (clientmodel == null)
                        {
                            clientdal.Add(c, new Model.tb_client_model()
                            {
                                ip = CommonHelper.GetDefaultIP(),
                                projectname = XXF.Common.XXFConfig.ProjectName,
                                serverid = context.ServiceModel.id,
                                sessionid = sessionid
                            });
                        }
                        else
                        {
                            clientdal.Edit(c, new Model.tb_client_model()
                            {
                                ip = CommonHelper.GetDefaultIP(),
                                projectname = XXF.Common.XXFConfig.ProjectName,
                                serverid = context.ServiceModel.id,
                                sessionid = sessionid
                            });
                        }
                        context.ClientModel = clientdal.Get(c, sessionid);

                    });
                    _context = context;
                    //建立心跳守护
                    if (_context.HeatBeatProtect == null)
                    {
                        ClientHeatBeatProtect clientHeatBeatProtect = new ClientHeatBeatProtect(_context);
                        _context.HeatBeatProtect = clientHeatBeatProtect;
                    }
                }
                LogHelper.Log(_context.ServiceModel.id, EnumLogType.Client, string.Format("客户端注册成功", ServiceNamespace));
            }
            catch (Exception exp)
            {
                LogHelper.Error(-1, EnumLogType.Client, string.Format("客户端注册失败,服务命名空间:{0}", ServiceNamespace), exp);
                throw exp;
            }
        }

        /// <summary>
        /// 获取当前客户端可用均衡节点信息
        /// </summary>
        /// <returns></returns>
        public LoadBalanceInfo GetLoadBalanceInfo()
        {
            try
            {
                if (_context.NodeModels == null || _context.NodeModels.Count == 0)
                    throw new ServiceCenterException(string.Format("当前负载均衡列表为空"));

                int allboost = 0;
                foreach (var m in _context.NodeModels)
                {
                    allboost += m.boostpercent;
                }
                Random rd = new Random(Guid.NewGuid().GetHashCode());
                int rdboost = rd.Next(0, allboost) + 1;//1-100
                int boost = 0;
                //俄罗斯罗盘的方式
                foreach (var m in _context.NodeModels)
                {
                    boost += m.boostpercent;
                    if (boost >= rdboost)
                    {
                        return new LoadBalanceInfo() { Host = m.ip, Port = m.port };
                    }
                }

                throw new ServiceCenterException(string.Format("负载均衡算法错误,总权重:{0},随机权重:{1}", allboost, rdboost));
            }
            catch (Exception exp)
            {
                LogHelper.Error(_context.ServiceModel.id, EnumLogType.Client, string.Format("负载均衡算法错误", ServiceNamespace), exp);
                throw exp;
            }
        }

        /// <summary>
        /// client移除异常节点
        /// </summary>
        /// <param name="servicenamespace">服务标识</param>
        /// <param name="host"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public bool RemoveNode(string servicenamespace, string host, int port)
        {
            try
            {
                return _context.NodeModels.Remove(_context.NodeModels.FirstOrDefault(s => s.servicenamespace == servicenamespace && s.ip == host && s.port == port));
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 获取当前客户端约定的（自定义）服务协议
        /// </summary>
        /// <returns></returns>
        public ServiceProtocal GetServiceProtocal()
        {
            return JsonConvert.DeserializeObject<ServiceProtocal>(_context.ProtocolVersionModel.protocoljson);
        }

        /// <summary>
        /// 获取服务命名空间
        /// </summary>
        /// <returns></returns>
        public string GetServiceNameSpace()
        {
            return _context.ServiceModel.servicenamespace;
        }

        /// <summary>
        /// 获取服务类型
        /// </summary>
        /// <returns></returns>
        public EnumServiceType GetServiceType()
        {
            return (EnumServiceType)_context.ServiceModel.servicetype;
        }

        public void Dispose()
        {
            try
            {
                if (_context != null)
                {
                    _context.HeatBeatProtect.Dispose();
                    SqlHelper.ExcuteSql(SystemConfigHelper.ServiceCenterConnectString, (c) =>
                    {
                        tb_client_dal clientdal = new tb_client_dal();
                        clientdal.Delete(c, _context.ClientModel.sessionid);
                    });
                    _context.HeatBeatProtect = null;
                    _context = null;
                }
            }
            catch (Exception exp)
            {
                LogHelper.Error(_context.ServiceModel.id, EnumLogType.Client, string.Format("客户端释放资源失败", ServiceNamespace), exp);
                throw exp;
            }
        }
    }

}
